package com.ch.base.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Random;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;

public class OtherUtils {
	/*
	 * #Java#
	 * 會處理#字元為%23，空白字元轉換為+，中文字拆開每BYTE處理為ASCII
	 * 第二個String為Locale
	 * java.net.URLEncoder.encode(String args,String args)
	 * java.net.URLDecoder.decode(String args,String args)

	 * #JavaScript#
	 * 會處理#字元為%23，空白字元轉換為+，中文字處理為UniCode
	 * escape(String args)
	 * unescape(String args)
	 * 不會處理#字元，空白字元轉換為%20，中文字拆開每BYTE處理為ASCII
	 * encodeURI(String args)
	 * decodeURI(String args)
	 * 會處理#字元為%23，空白字元轉換為%20，中文字拆開每BYTE處理為ASCII
	 * encodeURIComponent(String args)
	 * decodeURIComponent(String args)
	 */

	/**
	 * <b>字串加密</b><br/>
	 * 注意：此加密後結果如同 javascript escape 一致 
	 * @param 	origStr	欲加密之字串
	 * @return 	字串
	 */
	public static String escape(String origStr) {
		StringBuffer result = new StringBuffer();
		result.ensureCapacity(origStr.length() * 6);
		for (int i=0; i<origStr.length(); i++ ) {
			char j = origStr.charAt(i);
			if ((Character.isDigit(j)) || (Character.isLowerCase(j)) || (Character.isUpperCase(j))) {
				result.append(j);
			} else {
				if (j < 256) {
					result.append("%");
					if (j < 16) {
						result.append("0");
					}
					result.append(Integer.toString(j, 16));
				} else {
					result.append("%u");
					result.append(Integer.toString(j, 16));
				}
			}
		}
		return result.toString();
	}

	/**
	 * <b>字串解密</b><br/>
	 * 注意：此方法主要在於escape加密之相對解密 
	 * @param 	origStr	欲解密之字串
	 * @return 	字串
	 */
	public static String unescape(String origStr) {
		StringBuffer result = new StringBuffer();
		result.ensureCapacity(origStr.length());
		int lastPos = 0;
		int pos=0;
		char ch;
		while(lastPos < origStr.length()){
			pos = origStr.indexOf("%", lastPos);
			if (pos == lastPos) {
				if (origStr.charAt(pos+1) == 'u'){
					ch = (char)Integer.parseInt(origStr.substring(pos+2, pos+6), 16);
					result.append(ch);
					lastPos = pos + 6;
				}else{
					ch = (char)Integer.parseInt(origStr.substring(pos+1, pos+3), 16);
					result.append(ch);
					lastPos = pos + 3;
				}
			} else {
				if (pos == -1) {
					result.append(origStr.substring(lastPos));
					lastPos = origStr.length();
				} else {
					result.append(origStr.substring(lastPos, pos));
					lastPos = pos;
				}
			}
		}
		return result.toString();
	}

	/**
	 * <b>字串加密</b><br/>
	 * 注意：此加密後結果如同 javascript encodeURIComponent 一致 
	 * @param 	origStr	欲加密之字串
	 * @param	strCharset	字串之編碼(以utf-8為優)
	 * @return 	字串
	 */
	public static String URLEncoder(String origStr, String strCharset) {
		String result = "";
		try {
			result = URLEncoder.encode(origStr, strCharset);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * <b>字串解密</b><br/>
	 * 注意：此方法主要在於URLEncoder加密之相對解密 
	 * @param 	origStr	欲解密之字串
	 * @param	strCharset	字串之編碼，須與URLEncoder加密之編碼一致
	 * @return 	字串
	 */
	public static String URLDecoder(String origStr, String strCharset) {
		String result = "";
		try {
			result = URLDecoder.decode(origStr, strCharset);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * <b>字串加密</b><br/> 
	 * 注意：此方法不支援中文字串
	 * @param 	origStr	欲加密之字串
	 * @return 	字串
	 */
	public static String base64Encode(String origStr) throws Exception {
		String result = "";
		byte[] byteStr = origStr.getBytes();
		byte[] encodeData = new byte[origStr.length()];

		for (int i=0; i<byteStr.length ; i++) {
			encodeData[i] = (byte) (((byteStr[i]&15)<<4) + (byteStr[i]>>4));
		}
		result = new sun.misc.BASE64Encoder().encode(encodeData);
		return result;
	}

	/**
	 * <b>字串解密</b><br/>
	 * 注意：此方法主要在於base64Encode加密之相對解密 
	 * @param 	origStr	欲解密之字串
	 * @return 	字串
	 */
	public static String base64Decode(String origStr) throws Exception {
		String result = "";
		sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
		byte[] decodeData = decoder.decodeBuffer(origStr);

		for (int i=0; i<decodeData.length ; i++) {
			char decodeChar = (char) (((decodeData[i]&15)<<4) + ((decodeData[i]>>4)&15));
			result +=  decodeChar;
		}
		return result;
	}

	/**
	 * <b>日期時間亂數產生器</b><br/>
	 * @param 	decimal	欲取得亂數之長度
	 * @return 	字串
	 */
	public static String pokerRandom(int decimal) { 
		String result = "";
		Random random = new Random();
		int resultArray[] =  new int[7];
		Calendar today = Calendar.getInstance();
		resultArray[0] = Integer.parseInt(String.valueOf(today.get(Calendar.YEAR)));
		resultArray[1] = Integer.parseInt(String.valueOf(today.get(Calendar.MONTH) + 1));
		resultArray[2] = Integer.parseInt(String.valueOf(today.get(Calendar.DATE)));
		resultArray[3] = Integer.parseInt(String.valueOf(today.get(Calendar.HOUR)));
		resultArray[4] = Integer.parseInt(String.valueOf(today.get(Calendar.MINUTE)));
		resultArray[5] = Integer.parseInt(String.valueOf(today.get(Calendar.SECOND)));
		resultArray[6] = Integer.parseInt(String.valueOf(today.get(Calendar.MILLISECOND)));

		for (int i=0; i < resultArray.length; i ++) { // 這個迴圈也可以只跑到result.length/2
			int index = random.nextInt(7);
			//交換 i 跟index的原素
			int tmp = resultArray[index];
			resultArray[index] = resultArray[i];
			resultArray[i] = tmp;
		}

		for (int i=0; i < resultArray.length; i ++) {
			result += String.valueOf(resultArray[i]);
		}

		if (result.length() > decimal) {
			result = result.substring(0, decimal);
		} else {
			while (result.length() != decimal) {
				result += pokerRandom(decimal-result.length());
			}
		}
		return result;
	}

	/**
	 * <b>取得session之值</b><br/>
	 * @param 	sessionId	欲取得之session id
	 * @return 	Object物件
	 */
	public static Object getSession(String sessionId) {
		Object resultObj = null;
		HttpServletRequest request;
		HttpSession session;
		request = ServletActionContext.getRequest();
		session = request.getSession();

		resultObj = session.getAttribute(sessionId);
		return resultObj;
	}
	
	/**
	 * 產生不重複之鑑別字串
	 * @return	String 22位元 Unique字串 (0~9, a~z, A~Z)
	 */
	public static String getUUID() {
		//取得16進位randomUUID並移除'-'字元
		String strUUID = UUID.randomUUID().toString().replaceAll("-", "");
		strUUID = strUUID.toUpperCase();
		
		if(strUUID.length() != 32){
			//不符合字串長度
			return "";
		}
		
		String strRet = "";
		/*
		 * 依15, 15, 2的方式轉換字串
		 * 由16進位轉成62進位
		 * 產生 10, 10, 2字串相連成22長度之唯一字串
		 * 由0~9, a~z, A~Z組成
		 */
		for (int i = 0; i < 2; i++) {
			long sum = 0;
			for (int j = 0; j < 15; j++) {
				sum *= 16;
				char chr = strUUID.charAt(i * 15 + j);
				int ichr = (int)chr;
				if (ichr >= (int)('0') &&  ichr <= (int)('9')) {
					sum = sum + ichr - (int)('0') ;
				}else{
					sum = sum + ichr - (int)('A') + 10 ;
				}				
			}
			for(int j = 0; j < 10; j++) {
				long mod = sum % 62;
				sum = (long) Math.floor(sum / 62);
				if(mod < 10){
					strRet += (char)((int)'0' + mod);
				}else if(mod < 36){
					strRet += (char)((int)'a' + mod - 10);
				}else{
					strRet += (char)((int)'A' + mod - 36);
				}
			}
		}
		strRet += strUUID.charAt(30);
		strRet += strUUID.charAt(31);		
		strUUID = strRet;
		return strUUID;
	}
}
